import {
    CellState,
    ConnectionConstraint,
    ConnectionHandler,
    ConstraintHandler,
    Graph,
    ImageBox, InternalMouseEvent,
    Point,
    Shape
} from "@maxgraph/core";

interface ShapePort {
    x: number
    y: number
    perimeter: boolean
    constraint: string
}

const STYLE_SOURCE_PORT = 'sourcePort';
const STYLE_TARGET_PORT = 'targetPort';
export default function (graph: Graph) {
    // Shape.prototype
    const ports: Record<string, ShapePort> = {};
    ports['w'] = {x: 0, y: 0.5, perimeter: true, constraint: 'west'};
    ports['e'] = {x: 1, y: 0.5, perimeter: true, constraint: 'east'};
    ports['n'] = {x: 0.5, y: 0, perimeter: true, constraint: 'north'};
    ports['s'] = {x: 0.5, y: 1, perimeter: true, constraint: 'south'};
    // ports['nw'] = {x: 0, y: 0, perimeter: true, constraint: 'north west'};
    // ports['ne'] = {x: 1, y: 0, perimeter: true, constraint: 'north east'};
    // ports['sw'] = {x: 0, y: 1, perimeter: true, constraint: 'south west'};
    // ports['se'] = {x: 1, y: 1, perimeter: true, constraint: 'south east'};
    Shape.prototype.getPorts = function () {
        return ports;
    }
    const connectionHandler = graph.getPlugin('ConnectionHandler') as ConnectionHandler
    const constraintHandler = connectionHandler.constraintHandler as ConstraintHandler
    constraintHandler.pointImage = new ImageBox('/images/dot.gif', 10, 10)
    // @ts-ignore 如果不是port出来的连接点就不允许连接
    connectionHandler.isConnectableCell = function (cell) {
        return false;
    }
    connectionHandler.createEdgeState = function (me?: InternalMouseEvent) {
        const edge = graph.createEdge(null, '', null, null, null,
            {
                edgeStyle: 'orthogonalEdgeStyle',
                strokeWidth: 1.5,
                strokeColor: "black",
            });
        return new CellState(this.graph.view, edge, this.graph.getCellStyle(edge));
    }
    // @ts-ignore 设置如果从port引出的连接点，是不允许自动改变连接位置的
    const _updateEdgeState = connectionHandler.updateEdgeState;
    connectionHandler.updateEdgeState = function (pt: Point | null, constraint: ConnectionConstraint | null) {
        // console.log("updateEdgeState");
        // if (pt != null && this.previous != null) {
        //     const constraints = this.graph.getAllConnectionConstraints(this.previous, true);
        //     let nearestConstraint = null;
        //     let dist = null;
        //     const len = constraints?.length ?? 0;
        //     for (let i = 0; constraints && i < len; i++) {
        //         const cp = this.graph.getConnectionPoint(this.previous, constraints[i]);
        //         if (cp != null) {
        //             const tmp = (cp.x - pt.x) * (cp.x - pt.x) + (cp.y - pt.y) * (cp.y - pt.y);
        //             if (dist == null || tmp < dist) {
        //                 nearestConstraint = constraints[i];
        //                 dist = tmp;
        //             }
        //         }
        //     }
        //     if (nearestConstraint != null) {
        //         this.sourceConstraint = nearestConstraint;
        //     }
        console.log(constraint)
        _updateEdgeState.apply(this, [pt, constraint]);
            // In case the edge style must be changed during the preview:
            // this.edgeState.style.edgeStyle = 'orthogonalEdgeStyle';
            // And to use the new edge style in the new edge inserted into the graph,
            // update the cell style as follows:
            // this.edgeState.cell.style = utils.setStyle(this.edgeState.cell.style, 'edgeStyle', this.edgeState.style.edgeStyle);
        }


    // @ts-ignore 当鼠标经过或是有连线时要显示的可连接点
    graph.getAllConnectionConstraints = function (terminal, source) {
        if (terminal != null && terminal.shape != null &&
            terminal.shape.stencil != null) {
            // for stencils with existing constraints...
            if (terminal.shape.stencil) {
                return terminal.shape.stencil.constraints;
            }
        } else if (terminal != null && terminal.cell.isVertex()) {
            if (terminal.shape != null) {
                const ports = terminal.shape.getPorts();
                const cstrs: ConnectionConstraint[] = [];
                for (const id in ports) {
                    const port = ports[id];
                    const cstr = new ConnectionConstraint(
                        new Point(port.x, port.y), port.perimeter, id
                    );
                    // cstr.name = id;
                    cstrs.push(cstr);
                }
                return cstrs;
            }
        }
        return null;
    };
    graph.setConnectionConstraint = function (edge, terminal, source, constraint) {
        if (constraint != null) {
            const key = (source) ? STYLE_SOURCE_PORT : STYLE_TARGET_PORT;

            if (!constraint?.name) {
                this.setCellStyles(key, null, [edge]);
            } else if (!constraint.name) {
                this.setCellStyles(key, constraint.name, [edge]);
            }
        }
    };
    // @ts-ignore 返回给定连接的端口
    graph.getConnectionConstraint = function (edge, terminal, source) {
        const key = (source) ? STYLE_SOURCE_PORT : STYLE_TARGET_PORT;
        const id = edge.style[key] ?? '';
        if (!id) {
            const c = new ConnectionConstraint(null, false, id);
            return c;
        }
        return null;
    };

    // Returns the actual point for a port by redirecting the constraint to the port
    const graphGetConnectionPoint = graph.getConnectionPoint;
    graph.getConnectionPoint = function (vertex, constraint) {
        if (!constraint.name && vertex != null && vertex.shape != null) {
            const port: ShapePort = vertex.shape.getPorts()[constraint.name];
            if (port != null) {
                constraint = new ConnectionConstraint(new Point(port.x, port.y), port.perimeter);
            }
        }

        return graphGetConnectionPoint.apply(this, arguments);
    };


}